using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Drawing;
using FMOD;
using Freedb;
using Ripper;
using LeisureCenter.Api;
using LeisureCenter.Controls;

namespace FModPlayer
{
    public class FModAudioCdMedia : BaseFModMedia, IPlaylistMedia, IAudioCdMedia
    {
        private Sound cdSound;
        private int track;
        private int trackCount;
        private List<string> titles = new List<string>();
        private bool creatingSound;

        public FModAudioCdMedia(FModPlayer player, string fileName)
            : base(player, fileName)
        {
            this.track = -1;
        }

        public override MediaKind Kind { get { return MediaKind.CD; } }

        protected override void DoStop()
        {
            base.DoStop();
            if (cdSound != null)
            {
                this.cdSound.release();
                this.cdSound = null;
                this.player.FModSystem.setStreamBufferSize(16 * 1024, FMOD.TIMEUNIT.RAWBYTES);
            }
        }

        private void StopTrack()
        {
            base.DoStop();
        }

        protected override void CreateSoundIfNeeded()
        {
            if (!this.creatingSound)
            {
                this.creatingSound = true;
                try
                {
                    if (this.cdSound == null)
                    {
                        this.titles.Clear();
                        RetrieveInfosFromFreedb();
                        this.player.FModSystem.setStreamBufferSize(64 * 1024, FMOD.TIMEUNIT.RAWBYTES);
                        CheckResult(this.player.FModSystem.createSound(FileName[0] + ":", FMOD.MODE.HARDWARE | FMOD.MODE._2D | FMOD.MODE.CREATESTREAM, ref cdSound));
                        if (cdSound != null)
                        {
                            this.cdSound.getNumSubSounds(ref trackCount);
                            if (this.titles.Count != trackCount)
                            {
                                this.titles.Clear();
                                for (int i = 0; i < trackCount; i++)
                                {
                                    this.titles.Add(String.Format(@"Track {0:00}", i + 1));
                                }
                            }
                        }
                    }
                    if (this.sound == null && this.cdSound != null)
                    {
                        this.cdSound.getSubSound(this.track, ref sound);
                    }
                }
                finally
                {
                    this.creatingSound = false;
                }
            }
        }

        private void RetrieveInfosFromFreedb()
        {
            try
            {
                CDDrive drive = new CDDrive();
                if (!drive.Open(FileName[0]) || !drive.IsCDReady())
                    return;
                drive.LockCD();
                drive.Refresh();
                drive.UnLockCD();

                string query = drive.GetCDDBQuery();

                drive.Close();

                FreedbHelper freedb = new FreedbHelper();
                freedb.ClientName = "LeisureCenter";
                freedb.UserName = "LeisureCenter";
                freedb.Hostname = "www.cfagn.net";
                freedb.Version = "1.0";
                freedb.SetDefaultSiteAddress("fr.freedb.org");

                QueryResult queryResult;
                QueryResultCollection coll;
                string code = freedb.Query(query, out queryResult, out coll);

                //inexact match or multiple mathes show selection dialog
                if (code == FreedbHelper.ResponseCodes.CODE_210 ||
                    code == FreedbHelper.ResponseCodes.CODE_211)
                {
                    List<string> items = new List<string>();
                    foreach (QueryResult result in coll)
                    {
                        items.Add(result.Artist + " " + result.Title);
                    }
                    int index = 0;
                    if (!this.player.leisureCenterInstance.UIManager.ListDialog(items, true, ref index, Color.SkyBlue))
                        return;
                    queryResult = coll[index];
                }
                else
                if (code != FreedbHelper.ResponseCodes.CODE_200)
                    // not found
                    return;

                //queryResult now contains the results of our query.

                CDEntry cdEntry;
                code = freedb.Read(queryResult, out cdEntry);
                if (code != FreedbHelper.ResponseCodes.CODE_210)
                    return;

                foreach (Track trackEntry in cdEntry.Tracks)
                {
                    this.titles.Add(trackEntry.Title);
                }
            }
            catch (Exception ex)
            {
                Trace.TraceError(ex.Message);
            }
        }

        protected override void CreateChannelIfNeeded(bool paused)
        {
            CheckResult(player.FModSystem.playSound(CHANNELINDEX.FREE, sound, paused, ref channel));
            base.CreateChannelIfNeeded(paused);
        }

        #region IPlaylistMedia Membres

        public void Previous()
        {
            this.Track--;
        }

        public void Next()
        {
            this.Track++;
        }

        public IEnumerable<string> Titles 
        {
            get
            {
                CreateSoundIfNeeded();
                return this.titles; 
            }
        }

        public int Count { get { return this.trackCount; } }

        public string GetTitle(int index)
        {
            if (index >= 0 && index < titles.Count)
                return this.titles[index];
            else
                return "";
        }

        public event EventHandler ItemIndexChanged;

        public event EventHandler PlaylistChanged;

        #endregion

        #region IAudioCdMedia Membres

        public int Track
        {
            get { return this.track; }
            set
            {
                if (value < 0)
                    this.track = this.trackCount - 1;
                else
                if (value >= trackCount)
                    this.track = 0;
                else
                    this.track = value;
                StopTrack();
                this.duration = 0;
                DoPlay();
            }
        }

        #endregion
    }
}
